<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">
<meta name="referrer" content="same-origin">
<meta name="referrer" content="no-referrer" />








<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Java并发之旅," />










<meta name="description" content="开篇&amp;emsp;&amp;emsp;CountDownLatch的源码其实很简单，因为其主要依靠AQS实现（所以AQS不简单，大部分代码都会进入AQS讲解）。CountDownLatch由一个内部静态类Sync继承AQS。分析整个CountDownLatch的源码，抓住两个函数入口即可，一个是await(),一个是countDown()。当然为了熟悉这两个方法的环境，先来看下AQS的实现Sync：">
<meta name="keywords" content="Java并发之旅">
<meta property="og:type" content="article">
<meta property="og:title" content="Java并发之旅（一）CountDownLatch源码分析">
<meta property="og:url" content="http://yoursite.com/2018/07/30/Java基础（一）CountDownLatch源码分析/index.html">
<meta property="og:site_name" content="矩阵编程">
<meta property="og:description" content="开篇&amp;emsp;&amp;emsp;CountDownLatch的源码其实很简单，因为其主要依靠AQS实现（所以AQS不简单，大部分代码都会进入AQS讲解）。CountDownLatch由一个内部静态类Sync继承AQS。分析整个CountDownLatch的源码，抓住两个函数入口即可，一个是await(),一个是countDown()。当然为了熟悉这两个方法的环境，先来看下AQS的实现Sync：">
<meta property="og:locale" content="zh-Hans">
<meta property="og:updated_time" content="2019-10-24T16:22:00.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Java并发之旅（一）CountDownLatch源码分析">
<meta name="twitter:description" content="开篇&amp;emsp;&amp;emsp;CountDownLatch的源码其实很简单，因为其主要依靠AQS实现（所以AQS不简单，大部分代码都会进入AQS讲解）。CountDownLatch由一个内部静态类Sync继承AQS。分析整个CountDownLatch的源码，抓住两个函数入口即可，一个是await(),一个是countDown()。当然为了熟悉这两个方法的环境，先来看下AQS的实现Sync：">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/2018/07/30/Java基础（一）CountDownLatch源码分析/"/>





  <title>Java并发之旅（一）CountDownLatch源码分析 | 矩阵编程</title>
  





  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?7d29e6fba8e07d1a8af2414a20e5f2a6";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">矩阵编程</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-主页">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-主页"></i> <br />
            
            主页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-分类"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-所有文章">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-文章"></i> <br />
            
            所有文章
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/07/30/Java基础（一）CountDownLatch源码分析/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="matrix">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="矩阵编程">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Java并发之旅（一）CountDownLatch源码分析</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-07-30T13:48:28+08:00">
                2018-07-30
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Java并发之旅/" itemprop="url" rel="index">
                    <span itemprop="name">Java并发之旅</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2018/07/30/Java基础（一）CountDownLatch源码分析/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count"
                        data-disqus-identifier="2018/07/30/Java基础（一）CountDownLatch源码分析/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h3 id="开篇"><a href="#开篇" class="headerlink" title="开篇"></a>开篇</h3><p>&emsp;&emsp;CountDownLatch的源码其实很简单，因为其主要依靠<strong>AQS</strong>实现（所以AQS不简单，大部分代码都会进入AQS讲解）。CountDownLatch由一个内部静态类Sync继承AQS。分析整个CountDownLatch的源码，抓住两个函数入口即可，一个是<strong>await()</strong>,一个是<strong>countDown()</strong>。当然为了熟悉这两个方法的环境，先来看下AQS的实现Sync：<br><a id="more"></a><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.CountDownLatch.Sync</span><br><span class="line">private static final class Sync extends AbstractQueuedSynchronizer &#123;</span><br><span class="line">        private static final long serialVersionUID = 4982264981922014374L;</span><br><span class="line">        // AQS中鼎鼎有名的state</span><br><span class="line">        Sync(int count) &#123;</span><br><span class="line">            setState(count);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        int getCount() &#123;</span><br><span class="line">            return getState();</span><br><span class="line">        &#125;</span><br><span class="line">        // 这个方法会经常调用，如果state=0，证明可以唤醒等待线程了</span><br><span class="line">        protected int tryAcquireShared(int acquires) &#123;</span><br><span class="line">            return (getState() == 0) ? 1 : -1;</span><br><span class="line">        &#125;</span><br><span class="line">        // 尝试去释放锁，调用CountDown()方法会调用此方法，将state-1</span><br><span class="line">        protected boolean tryReleaseShared(int releases) &#123;</span><br><span class="line">            // Decrement count; signal when transition to zero</span><br><span class="line">            for (;;) &#123;</span><br><span class="line">                int c = getState();</span><br><span class="line">                if (c == 0)</span><br><span class="line">                    return false;</span><br><span class="line">                int nextc = c-1;</span><br><span class="line">                if (compareAndSetState(c, nextc))</span><br><span class="line">                    return nextc == 0;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="await-方法"><a href="#await-方法" class="headerlink" title="await()方法"></a>await()方法</h3><p>&emsp;&emsp;下面直面主题，先来看下<strong>await()</strong>方法具体做了什么事，其实具体还是调用了AQS中的方法，我是代码的搬运工：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.CountDownLatch.Sync</span><br><span class="line">public void await() throws InterruptedException &#123;</span><br><span class="line">        sync.acquireSharedInterruptibly(1);</span><br><span class="line">&#125;</span><br><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">public final void acquireSharedInterruptibly(int arg)</span><br><span class="line">            throws InterruptedException &#123;</span><br><span class="line">        if (Thread.interrupted())</span><br><span class="line">            throw new InterruptedException();</span><br><span class="line">        // 参见Sync中的代码解释，第一次进来，如果不需要等待，await线程就直接进行下去了，不需要阻塞</span><br><span class="line">        if (tryAcquireShared(arg) &lt; 0)</span><br><span class="line">            doAcquireSharedInterruptibly(arg);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p><strong>doAcquireSharedInterruptibly()</strong> 是重点方法（后面会讲到很多次，这个大概就是迷宫的入口了），讲这个方法之前，简单说一下AQS，我是代码的搬运工（网上抄一份，解释的比我通顺多了）<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line">//java.util.concurrent.locks.AbstractQueuedSynchronizer.Node</span><br><span class="line">    ...................</span><br><span class="line">/**</span><br><span class="line"> * Node 是AQS的内部静态类</span><br><span class="line"> * AQS主要的概念就是队列，队列里面就是节点，节点差不多长这个样子 </span><br><span class="line"> */</span><br><span class="line">static final class Node &#123;</span><br><span class="line">    /** waitStatus value to indicate thread has cancelled */</span><br><span class="line">    static final int CANCELLED =  1;</span><br><span class="line">    /** waitStatus value to indicate successor&apos;s thread needs unparking */</span><br><span class="line">    static final int SIGNAL    = -1;</span><br><span class="line">    /** waitStatus value to indicate thread is waiting on condition */</span><br><span class="line">    static final int CONDITION = -2;</span><br><span class="line">    /**</span><br><span class="line">     * waitStatus value to indicate the next acquireShared should</span><br><span class="line">     * unconditionally propagate</span><br><span class="line">     */</span><br><span class="line">    static final int PROPAGATE = -3; </span><br><span class="line">    /** Marker to indicate a node is waiting in shared mode */</span><br><span class="line">    static final Node SHARED = new Node();</span><br><span class="line">    /** Marker to indicate a node is waiting in exclusive mode */</span><br><span class="line">    static final Node EXCLUSIVE = null;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">    *注意：</span><br><span class="line">    *分为两种类型的结点：共享模式结点 与 排他模式结点。</span><br><span class="line">    *对于任何类型的结点，初始状态waitStatus均为0</span><br><span class="line">     等待状态：</span><br><span class="line">     *-SIGNAL(-1):</span><br><span class="line">     *  后继结点处于等待状态，</span><br><span class="line">     *  如果当前线程释放的同步状态或者被中断，</span><br><span class="line">     *  将会通知后继结点，使后继结点线程运行</span><br><span class="line">     * </span><br><span class="line">     *-CANCELLED(1):</span><br><span class="line">     *  同步队列中等待的线程等待超时或者被中断，需要从同步队列中取消等待</span><br><span class="line">     *</span><br><span class="line">     *-CONDITION(-2):</span><br><span class="line">     *  结点在等待队列中，结点线程等待在这个Condition上，</span><br><span class="line">     *  当其他线程对这个Condition对象调用signal()\signalAll()，</span><br><span class="line">     *  则这个结点将进入等待队列中移入同步队列中，准备重试获取同步状态;</span><br><span class="line">     *</span><br><span class="line">     *-PROPAGATE(-3)</span><br><span class="line">     *</span><br><span class="line">     *-INITIAL(0):</span><br><span class="line">     *  初始状态</span><br><span class="line">     *</span><br><span class="line">     *</span><br><span class="line">     *;PROPAGATE;</span><br><span class="line">     */</span><br><span class="line">    volatile int waitStatus;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 前驱结点 </span><br><span class="line">     */</span><br><span class="line">    volatile Node prev;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 后继结点</span><br><span class="line">     */</span><br><span class="line">    volatile Node next;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 获取同步状态的线程</span><br><span class="line">     */</span><br><span class="line">    volatile Thread thread;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 等待队列中的后继结点。</span><br><span class="line">     */</span><br><span class="line">    Node nextWaiter;</span><br><span class="line">    ...................</span><br></pre></td></tr></table></figure></p>
<p>下面再来看看AQS长啥样，主要看AQS三个参数，其他的先忽略了<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">// 因为AQS就是队列，这里就是队列的头结点</span><br><span class="line">private transient volatile Node head;</span><br><span class="line">// 队列的尾节点</span><br><span class="line">private transient volatile Node tail;</span><br><span class="line">// 鼎鼎有名的 state（CountDownLatch中count就是这个state）</span><br><span class="line">private volatile int state;</span><br></pre></td></tr></table></figure></p>
<p>再来看下主角方法：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">private void doAcquireSharedInterruptibly(int arg)</span><br><span class="line">        throws InterruptedException &#123;</span><br><span class="line">        // 加入AQS豪华队列阵容</span><br><span class="line">        final Node node = addWaiter(Node.SHARED);</span><br><span class="line">        boolean failed = true;</span><br><span class="line">        try &#123;</span><br><span class="line">            for (;;) &#123;</span><br><span class="line">                final Node p = node.predecessor();</span><br><span class="line">                if (p == head) &#123;</span><br><span class="line">                    int r = tryAcquireShared(arg);</span><br><span class="line">                    if (r &gt;= 0) &#123;</span><br><span class="line">                        setHeadAndPropagate(node, r);</span><br><span class="line">                        p.next = null; // help GC</span><br><span class="line">                        failed = false;</span><br><span class="line">                        return;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                if (shouldParkAfterFailedAcquire(p, node) &amp;&amp;</span><br><span class="line">                    parkAndCheckInterrupt())</span><br><span class="line">                    throw new InterruptedException();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; finally &#123;</span><br><span class="line">            if (failed)</span><br><span class="line">                cancelAcquire(node);</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>逐行代码分析，这个方法一开头先加入一个<strong>SHARED</strong>节点，SHARED节点在Node中是一个常量，于此还有一个<strong>EXCLUSIVE</strong>节点，顾名思义，一个代表共享，一个代表独占。<br>先来看一下<strong>addWaiter()</strong>方法干了什么：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">// 上面传来的是 SHARED 节点，这里直接调用Node的构造函数，</span><br><span class="line">// 将Node里面的nextWaiter设置为SHARED，这里没什么用，略过</span><br><span class="line">// 刚进来反正这里tail=null,我们直接看下面的enq方法</span><br><span class="line">// 返回SHARED节点</span><br><span class="line">private Node addWaiter(Node mode) &#123; </span><br><span class="line">        Node node = new Node(Thread.currentThread(), mode);</span><br><span class="line">        Node pred = tail;</span><br><span class="line">        if (pred != null) &#123;</span><br><span class="line">            node.prev = pred;</span><br><span class="line">            if (compareAndSetTail(pred, node)) &#123;</span><br><span class="line">                pred.next = node;</span><br><span class="line">                return node;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        enq(node);</span><br><span class="line">        return node;</span><br><span class="line">&#125;</span><br><span class="line">// 入队操作来了，AQS中喜闻乐见，先来一个死循环。</span><br><span class="line">// 这个方法很绕啊，我们第一次进来，tail=null，直接看compareAndSetHead </span><br><span class="line">// compareAndSetHead其实是使用CAS设置AQS的头结点，这里把新建的Node赋给head头结点</span><br><span class="line">// 顺便把新建的Node也赋给了AQS的tail尾节点</span><br><span class="line">// 这还不够，因为在for中循环，我们重来一次，现在 tail != null 了</span><br><span class="line">// 这里把刚传递进来的SHARED节点的prev参数指向刚才新建的Node节点</span><br><span class="line">// 然后又把SHARED节点赋给了tail节点（compareAndSetTail当然是用CAS为tail赋值）</span><br><span class="line">// 然后新建的Node节点的next参数指向了SHARED节点，返回了新建的Node节点（即head）</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 来来去去，好了AQS内部的队列模型出来了，CountDownLatch好像并没有发挥AQS队列的威力</span><br><span class="line"> * 就是这么简单了</span><br><span class="line"> *</span><br><span class="line"> *      +---------+       +------+ </span><br><span class="line"> * head |新建的Node|       |SHARED|  tail</span><br><span class="line">        |  next   |&lt;-----&gt;| pre  |</span><br><span class="line"> *      +---------+       +------+  </span><br><span class="line"> **/</span><br><span class="line">private Node enq(final Node node) &#123;</span><br><span class="line">        for (;;) &#123;</span><br><span class="line">            Node t = tail;</span><br><span class="line">            if (t == null) &#123; // Must initialize</span><br><span class="line">                if (compareAndSetHead(new Node()))</span><br><span class="line">                    tail = head;</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                node.prev = t;</span><br><span class="line">                if (compareAndSetTail(t, node)) &#123;</span><br><span class="line">                    t.next = node;</span><br><span class="line">                    return t;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>又进入恐怖游轮，我们回过头再看<strong>doAcquireSharedInterruptibly()</strong>方法内部中的死循环。第一次循环演练，我们拿SHARED节点的前置节点，看AQS队列可知是head节点，方便查看，再复制一遍代码：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">private void doAcquireSharedInterruptibly(int arg)</span><br><span class="line">        throws InterruptedException &#123;</span><br><span class="line">        // 前面已经加入AQS豪华队列阵容</span><br><span class="line">        final Node node = addWaiter(Node.SHARED);</span><br><span class="line">        boolean failed = true;</span><br><span class="line">        try &#123;</span><br><span class="line">            // 星辰大海，从for循环的第一次说起</span><br><span class="line">            for (;;) &#123;</span><br><span class="line">                // 首次循环 拿到SHARED节点的前置节点，当然就是head节点了</span><br><span class="line">                final Node p = node.predecessor();</span><br><span class="line">                // 表达式成立，进入这个if中</span><br><span class="line">                if (p == head) &#123;</span><br><span class="line">                    // 再次查看state状态</span><br><span class="line">                    // tryAcquireShared 返回就两个值 如果需要阻塞，r=-1，不需要阻塞，r=1</span><br><span class="line">                    int r = tryAcquireShared(arg);</span><br><span class="line">                    // 不需要阻塞了，await线程接下去要干啥</span><br><span class="line">                    // 剧透一下，其实接下来的代码啥也没干，await线程不阻塞了能干嘛</span><br><span class="line">                    // 看这个方法直接return出死循环，自己去干自己的事情了</span><br><span class="line">                    if (r &gt;= 0) &#123;</span><br><span class="line">                        setHeadAndPropagate(node, r);</span><br><span class="line">                        p.next = null; // help GC</span><br><span class="line">                        failed = false;</span><br><span class="line">                        return;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                if (shouldParkAfterFailedAcquire(p, node) &amp;&amp;</span><br><span class="line">                    parkAndCheckInterrupt())</span><br><span class="line">                    throw new InterruptedException();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; finally &#123;</span><br><span class="line">            if (failed)</span><br><span class="line">                cancelAcquire(node);</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>看到await线程不需要阻塞，来看看具体干了啥事，只要看下<strong>setHeadAndPropagate()</strong>这个方法，代码的搬运工：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">/**</span><br><span class="line"> * 参数node是addWaiter方法返回值，即SHARED节点，propagate=1</span><br><span class="line"> * 这个方法其实主要是释放AQS队列，后面会继续讲到如何释放</span><br><span class="line">**/</span><br><span class="line">private void setHeadAndPropagate(Node node, int propagate) &#123;</span><br><span class="line">        Node h = head; // Record old head for check below</span><br><span class="line">        // 把 SHARED 节点给了head</span><br><span class="line">        setHead(node);</span><br><span class="line">        // 这个方法直接进来了，因为propagate=1</span><br><span class="line">        if (propagate &gt; 0 || h == null || h.waitStatus &lt; 0 ||</span><br><span class="line">            (h = head) == null || h.waitStatus &lt; 0) &#123;</span><br><span class="line">            Node s = node.next;</span><br><span class="line">            // SHARED 节点的next节点为空，doReleaseShared方法调用</span><br><span class="line">            if (s == null || s.isShared())</span><br><span class="line">                doReleaseShared();</span><br><span class="line">        &#125;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure></p>
<p>强行再进入到doReleaseShared() 方法中看一下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">private void doReleaseShared() &#123;</span><br><span class="line">        // 又见迷之死循环</span><br><span class="line">        // 这个方法好像啥也没干…直接break跳出死循环</span><br><span class="line">        // 没关系，我们还会见面的</span><br><span class="line">        for (;;) &#123;</span><br><span class="line">            Node h = head;</span><br><span class="line">            // 这个方法进不来了，因为上一步把 SHARED 节点给了head</span><br><span class="line">            // tail节点也是 SHARED 哦</span><br><span class="line">            if (h != null &amp;&amp; h != tail) &#123;</span><br><span class="line">                int ws = h.waitStatus;</span><br><span class="line">                if (ws == Node.SIGNAL) &#123;</span><br><span class="line">                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))</span><br><span class="line">                        continue;            // loop to recheck cases</span><br><span class="line">                    unparkSuccessor(h);</span><br><span class="line">                &#125;</span><br><span class="line">                else if (ws == 0 &amp;&amp;</span><br><span class="line">                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))</span><br><span class="line">                    continue;                // loop on failed CAS</span><br><span class="line">            &#125;</span><br><span class="line">            if (h == head)                   // loop if head changed</span><br><span class="line">                break;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>一顿操作，其实啥事也没干哦，接下来再看下<strong>doAcquireSharedInterruptibly()</strong> 方法中的 <strong>shouldParkAfterFailedAcquire()</strong> 函数干了啥：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">// 参数pred为head节点 </span><br><span class="line">// 参数node为SHARED节点</span><br><span class="line">private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) &#123;</span><br><span class="line">        // head节点的waitStatus一直没设置过哦，初始默认为0</span><br><span class="line">        // ws=0，进入最后一个else</span><br><span class="line">        int ws = pred.waitStatus;</span><br><span class="line">        if (ws == Node.SIGNAL)</span><br><span class="line">            return true;</span><br><span class="line">        if (ws &gt; 0) &#123;</span><br><span class="line">            do &#123;</span><br><span class="line">                node.prev = pred = pred.prev;</span><br><span class="line">            &#125; while (pred.waitStatus &gt; 0);</span><br><span class="line">            pred.next = node;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            // 把head结点的 waitStatus设置为SIGNAL，从今以后，head节点的waitStatus=SIGNAL了</span><br><span class="line">            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);</span><br><span class="line">        &#125;</span><br><span class="line">        return false;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>言归正传，继续看 <strong>doAcquireSharedInterruptibly()</strong>方法，这次我们假设 <strong>tryAcquireShared()</strong>返回-1，接下来要阻塞了，看一下上面 <strong>doAcquireSharedInterruptibly()</strong>函数，需要阻塞的时候，竟然还是会调用 <strong>shouldParkAfterFailedAcquire()</strong>，哦，接下来发生的事情一模一样，我们head结点的waitStatus被设置为了SIGNAL，并且由于shouldParkAfterFailedAcquire返回false，我们会第二次进入循环中。再次进入循环的话，当然我们还是假设await线程会阻塞（因为不会阻塞的话就直接跳出循环了），这次 <strong>shouldParkAfterFailedAcquire()</strong>不负众望，head节点的waitStatus因为在第一次循环被设置为了SIGNAL，这个方法直接返回true了，很好，我们进入 <strong>parkAndCheckInterrupt()</strong>方法。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">// await线程终于可以休息了</span><br><span class="line">// LockSupport.park的意思就是把当前线程挂起</span><br><span class="line">// 调用await方法的线程，整个世界在这里被暂停了</span><br><span class="line">private final boolean parkAndCheckInterrupt() &#123;</span><br><span class="line">        LockSupport.park(this);</span><br><span class="line">        return Thread.interrupted();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>好了，awiat()方法到这里暂停了，await整个线程被阻塞在这里，注意，线程是被阻塞在for循环里面，一旦被唤醒，继续迷之循环。</p>
<h3 id="countDown-方法"><a href="#countDown-方法" class="headerlink" title="countDown()方法"></a>countDown()方法</h3><p>到这里我们终于可以松口气，看下两大重要方法中的另外一个方法<strong>countDown()</strong>，这个方法比较简单，就是调用了Sync类中的：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">// 每次调用countDown()，就是释放一下共享锁</span><br><span class="line">// 这里传入的arg参数恒为1</span><br><span class="line">public final boolean releaseShared(int arg) &#123;</span><br><span class="line">        // 如果启动await线程，会调用doReleaseShared，这个方法上面遇到过了，老朋友。</span><br><span class="line">        if (tryReleaseShared(arg)) &#123;</span><br><span class="line">            doReleaseShared();</span><br><span class="line">            return true;</span><br><span class="line">        &#125;</span><br><span class="line">        return false;</span><br><span class="line">&#125;</span><br><span class="line">// java.util.concurrent.CountDownLatch.Sync</span><br><span class="line">// releases参数恒为1</span><br><span class="line">// state=0会返回true，代表await线程可以满血复活了</span><br><span class="line">protected boolean tryReleaseShared(int releases) &#123;</span><br><span class="line">            // 迷之死循环，CAS交换的温室</span><br><span class="line">            for (;;) &#123;</span><br><span class="line">                int c = getState();</span><br><span class="line">                // 非法调用countDown()太多次了，怎么能忍心让state成为负数，随便返回个false给你</span><br><span class="line">                if (c == 0)</span><br><span class="line">                    return false;</span><br><span class="line">                // 让state（其实就是count）减1，然后CAS交换</span><br><span class="line">                int nextc = c-1;</span><br><span class="line">                if (compareAndSetState(c, nextc))</span><br><span class="line">                    return nextc == 0;</span><br><span class="line">            &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 再贴一下老朋友</span><br><span class="line">// 不过上一次见面，他什么都没干，终于又见面了</span><br><span class="line">/**</span><br><span class="line"> * 顺便再看下我们AQS的队列</span><br><span class="line"> *</span><br><span class="line"> *      +---------+       +------+ </span><br><span class="line"> * head |新建的Node|       |SHARED|  tail</span><br><span class="line">        |  next   |&lt;-----&gt;| pre  |</span><br><span class="line"> *      +---------+       +------+  </span><br><span class="line"> **/</span><br><span class="line">private void doReleaseShared() &#123;</span><br><span class="line">        for (;;) &#123;</span><br><span class="line">            // 反正这里 h == head 都成立，最后总能结束</span><br><span class="line">            Node h = head;</span><br><span class="line">            // head=Node  tail=SHARED</span><br><span class="line">            // 第一次进来等式肯定成立的，进去看看</span><br><span class="line">            // 剧透：从后面看如果await线程已经被其他线程唤醒了，就会变成head=tail=SHARED</span><br><span class="line">            if (h != null &amp;&amp; h != tail) &#123;</span><br><span class="line">                int ws = h.waitStatus;</span><br><span class="line">                // head节点的waitStatus早就是SIGNAL了，等式成立，再进去看看</span><br><span class="line">                if (ws == Node.SIGNAL) &#123;</span><br><span class="line">                    // 如果head的waitStatus已经被别人篡改了</span><br><span class="line">                    // 那么啥事也不做，继续循环</span><br><span class="line">                    // 如果当前countDown线程顺利的话，head的waitStatus=SIGNAL,CAS交换成功了</span><br><span class="line">                    // 严正警戒：这个时候head节点的waitStatus=0一切又重归原样</span><br><span class="line">                    // 最后调用unparkSuccessor()</span><br><span class="line">                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))</span><br><span class="line">                        continue;            // loop to recheck cases</span><br><span class="line">                    unparkSuccessor(h);</span><br><span class="line">                &#125;</span><br><span class="line">                else if (ws == 0 &amp;&amp;</span><br><span class="line">                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))</span><br><span class="line">                    continue;                // loop on failed CAS</span><br><span class="line">            &#125;</span><br><span class="line">            if (h == head)                   // loop if head changed</span><br><span class="line">                break;</span><br><span class="line">        &#125;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure></p>
<p>假设线程一切顺利，<strong>unparkSuccessor()</strong>方法被调用：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">// node参数为head节点，注意他的waitStatus因为CAS交换，又变为0了</span><br><span class="line">// 这个方法存在的意义，当然是唤醒我们的await线程了</span><br><span class="line">private void unparkSuccessor(Node node) &#123;</span><br><span class="line">        int ws = node.waitStatus;</span><br><span class="line">        if (ws &lt; 0)</span><br><span class="line">            compareAndSetWaitStatus(node, ws, 0);</span><br><span class="line">        // head的下一个节点，当然是SHARED(tail)节点了</span><br><span class="line">        Node s = node.next;</span><br><span class="line">        // 很遗憾都不成立</span><br><span class="line">        if (s == null || s.waitStatus &gt; 0) &#123;</span><br><span class="line">            s = null;</span><br><span class="line">            for (Node t = tail; t != null &amp;&amp; t != node; t = t.prev)</span><br><span class="line">                if (t.waitStatus &lt;= 0)</span><br><span class="line">                    s = t;</span><br><span class="line">        &#125;</span><br><span class="line">        // 好了，一切顺利的结局，await线程被唤醒。</span><br><span class="line">        if (s != null)</span><br><span class="line">            LockSupport.unpark(s.thread);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>await线程被唤醒了，前面说了await线程其实一直被阻塞在一个for循环里面，一旦被人唤醒，迷之for循环又开始了，还是再贴一遍<strong>doAcquireSharedInterruptibly()</strong>这个方法：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line">// java.util.concurrent.locks.AbstractQueuedSynchronizer</span><br><span class="line">private void doAcquireSharedInterruptibly(int arg)</span><br><span class="line">        throws InterruptedException &#123;</span><br><span class="line">        final Node node = addWaiter(Node.SHARED);</span><br><span class="line">        boolean failed = true;</span><br><span class="line">        try &#123;</span><br><span class="line">            for (;;) &#123;</span><br><span class="line">                // await方法被唤醒，再次进入循环</span><br><span class="line">                // 拿到SHARED节点的前置节点，当然还是head节点了</span><br><span class="line">                final Node p = node.predecessor();</span><br><span class="line">                if (p == head) &#123;</span><br><span class="line">                    // 这里的r当然是1了，因为我们是被唤醒的，被唤醒的条件就是tryAcquireShared返回1</span><br><span class="line">                    int r = tryAcquireShared(arg);</span><br><span class="line">                    // 似曾相识，我们再次进入这个方法，其实后面要发生的事情前面已经说过了</span><br><span class="line">                    // head节点next指针，</span><br><span class="line">                    if (r &gt;= 0) &#123;</span><br><span class="line">                        // 把head指向SHARED，释放新建的Node</span><br><span class="line">                        // 从此以后，head==tail==SHARED</span><br><span class="line">                        setHeadAndPropagate(node, r);</span><br><span class="line">                        // 这里新建的Node的next指针不再指向SHARED了</span><br><span class="line">                        // 这个help GC感觉没什么用哦</span><br><span class="line">                        p.next = null; // help GC</span><br><span class="line">                        failed = false;</span><br><span class="line">                        return;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                if (shouldParkAfterFailedAcquire(p, node) &amp;&amp;</span><br><span class="line">                    parkAndCheckInterrupt())</span><br><span class="line">                    throw new InterruptedException();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; finally &#123;</span><br><span class="line">            if (failed)</span><br><span class="line">                cancelAcquire(node);</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 顺便再看下我们AQS的队列</span><br><span class="line"> *</span><br><span class="line"> *      +---------+       +------+ </span><br><span class="line"> * head |新建的Node|       |SHARED|  tail</span><br><span class="line">        |  next   |&lt;-----&gt;| pre  |</span><br><span class="line"> *      +---------+       +------+  </span><br><span class="line"> *</span><br><span class="line"> * 经过这个方法之后，我们的队列就变成了这样（SHARED不需要被释放，因为他是静态常量）</span><br><span class="line"> *</span><br><span class="line"> *      +---------+</span><br><span class="line"> * head | SHARED  | tail</span><br><span class="line"> *      |         |</span><br><span class="line"> *      +---------+</span><br><span class="line"> *</span><br><span class="line"> *</span><br><span class="line"> * 参数node是addWaiter方法返回值，即SHARED节点，propagate=1</span><br><span class="line"> * </span><br><span class="line"> * 把head指向SHARED，释放新建的Node，释放线程引用</span><br><span class="line"> *</span><br><span class="line">**/</span><br><span class="line">private void setHeadAndPropagate(Node node, int propagate) &#123;</span><br><span class="line">        Node h = head; // Record old head for check below</span><br><span class="line">        // 把 SHARED 节点给了head</span><br><span class="line">        // 并且把SHARED的pre置为null（如此这般就释放了之前新建的Node节点）</span><br><span class="line">        setHead(node);</span><br><span class="line">        // 这个方法直接进来了，因为propagate=1</span><br><span class="line">        if (propagate &gt; 0 || h == null || h.waitStatus &lt; 0 ||</span><br><span class="line">            (h = head) == null || h.waitStatus &lt; 0) &#123;</span><br><span class="line">            Node s = node.next;</span><br><span class="line">            // SHARED 节点的next节点为空，doReleaseShared方法调用</span><br><span class="line">            if (s == null || s.isShared())</span><br><span class="line">                doReleaseShared();</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">private void setHead(Node node) &#123;</span><br><span class="line">        head = node;</span><br><span class="line">        node.thread = null;</span><br><span class="line">        node.prev = null;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>&emsp;&emsp;学习了Doug Lea大神的源码后，什么函数式编程，面向对象编程，一切都觉过眼云烟，所有的函数方法存在的意义，都是为了重用。你在层层重用面前，从这个方法跳到另外一个方法，当你觉得终于达到了终点的时候，一切其实又回到了原点。</p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/Java并发之旅/" rel="tag"># Java并发之旅</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2018/07/28/Netty之旅（三）ByteBuf内存管理/" rel="next" title="Netty之旅（三）ByteBuf内存三剑客以及算法概要">
                <i class="fa fa-chevron-left"></i> Netty之旅（三）ByteBuf内存三剑客以及算法概要
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2018/08/08/Netty之旅（四）ByteBuf内存管理之PoolChunk/" rel="prev" title="Netty之旅（四）ByteBuf内存管理之PoolChunk">
                Netty之旅（四）ByteBuf内存管理之PoolChunk <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  
    <div class="comments" id="comments">
      <div id="disqus_thread">
        <noscript>
          Please enable JavaScript to view the
          <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a>
        </noscript>
      </div>
    </div>

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">matrix</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives">
              
                  <span class="site-state-item-count">47</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">18</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                
                  <span class="site-state-item-count">19</span>
                  <span class="site-state-item-name">标签</span>
                
              </div>
            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-3"><a class="nav-link" href="#开篇"><span class="nav-number">1.</span> <span class="nav-text">开篇</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#await-方法"><span class="nav-number">2.</span> <span class="nav-text">await()方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#countDown-方法"><span class="nav-number">3.</span> <span class="nav-text">countDown()方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#总结"><span class="nav-number">4.</span> <span class="nav-text">总结</span></a></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">matrix</span>

  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.4</div>
<div class=BbeiAn-info">
  浙ICP备 -
  <a href="http://www.beian.miit.gov.cn">18040498号</a>
  </a>
</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  

    
      <script id="dsq-count-scr" src="https://luyun.disqus.com/count.js" async></script>
    

    
      <script type="text/javascript">
        var disqus_config = function () {
          this.page.url = 'http://yoursite.com/2018/07/30/Java基础（一）CountDownLatch源码分析/';
          this.page.identifier = '2018/07/30/Java基础（一）CountDownLatch源码分析/';
          this.page.title = 'Java并发之旅（一）CountDownLatch源码分析';
        };
        var d = document, s = d.createElement('script');
        s.src = 'https://luyun.disqus.com/embed.js';
        s.setAttribute('data-timestamp', '' + +new Date());
        (d.head || d.body).appendChild(s);
      </script>
    

  




	





  














  





  

  

  

  
  

  

  

  

</body>
</html>
